package zhaomh.zhlib.util;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

public class ClassUtil {

    private static List<Class<?>> loadClasses(List<File> classes, String scan) throws ClassNotFoundException {
        List<Class<?>> clazzes = new ArrayList<>();
        for (File file : classes) {
            // 获取文件的绝对路径，并将反斜杠替换为正斜杠以确保跨平台兼容性
            String fPath = file.getAbsolutePath().replaceAll("\\\\", "/");
            // 计算相对于扫描路径的包名部分
            String packageName = fPath.substring(fPath.lastIndexOf(scan));
            // 去除.class后缀并使用点号代替路径分隔符以构造完整的类名
            packageName = packageName.replace(".class", "").replaceAll("/", ".");
            // 加载类并添加到结果列表中
            clazzes.add(Class.forName(packageName));
        }
        return clazzes;
    }

    private static void listFiles(File dir, List<File> fileList) {
        if (dir.isDirectory()) {
            // 如果是目录，则迭代其内容
            for (File f : dir.listFiles()) {
                listFiles(f, fileList);
            }
        } else {
            // 如果不是目录并且文件是以.class结尾，则添加到列表
            if (dir.getName().endsWith(".class")) {
                fileList.add(dir);
            }
        }
    }

    /**
     * 根据给定的包名（用点号分隔），查找并加载该包下所有的类文件。
     *
     * 此方法首先将包名转换为资源路径格式（用斜杠分隔），然后通过类加载器检索对应路径下的资源。
     * 对于每个找到的资源URL，如果它的协议是"file"，则会进一步解析它，收集所有的.class文件，
     * 并调用loadClasses方法来加载这些类。
     *
     * @param scan 指定要扫描的包名，例如 "com.example"
     * @return 包含所加载类的列表，如果未找到任何类，则可能返回null
     * @throws IOException            如果读取资源失败
     * @throws ClassNotFoundException 如果无法找到或加载指定名称的类
     */
    public static List<Class<?>> loadClassFiles(String scan) throws IOException, ClassNotFoundException {
        // 将包名中的点号替换为斜杠以匹配资源路径格式
        scan = scan.replaceAll("\\.", "/");
        // 获取指定路径下的所有资源URL
        Enumeration<URL> dirs = Thread.currentThread().getContextClassLoader().getResources(scan);
        List<Class<?>> result = null;

        while (dirs.hasMoreElements()) {
            URL url = dirs.nextElement();
            // 只处理文件系统中的资源
            if ("file".equals(url.getProtocol())) {
                List<File> classes = new ArrayList<>();
                // 收集所有的.class文件
                listFiles(new File(url.getFile()), classes);
                // 加载收集到的类
                result = loadClasses(classes, scan);
                break; // 假设只处理第一个找到的文件系统路径
            }
        }
        return result;
    }
}